package com.pai4j.log.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pai4j.common.helper.SessionHelper;
import com.pai4j.common.util.SpringContextUtil;
import com.pai4j.log.constants.LogConstants;
import com.pai4j.log.entity.OperationLogEntity;
import com.pai4j.log.enums.LogStatusEnum;
import com.pai4j.log.enums.LogTypeEnum;
import com.pai4j.log.service.ILogService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.UUID;

/**
 * JSON工具类
 */
class JsonUtil {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static String toJsonString(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            return obj != null ? obj.toString() : null;
        }
    }
}

/**
 * 日志工具类
 * 提供简单易用的日志记录API
 *
 * @author: CYM-pai
 * @date: 2025/07/29 15:40
 **/
@Slf4j
public class LogUtil {

    /**
     * 记录操作日志
     *
     * @param module      模块名称
     * @param operation   操作类型
     * @param description 操作描述
     */
    public static void operation(String module, String operation, String description) {
        operation(module, operation, description, null, null);
    }

    /**
     * 记录操作日志（带参数）
     *
     * @param module      模块名称
     * @param operation   操作类型
     * @param description 操作描述
     * @param params      操作参数
     */
    public static void operation(String module, String operation, String description, Object params) {
        operation(module, operation, description, params, null);
    }

    /**
     * 记录操作日志（完整参数）
     *
     * @param module      模块名称
     * @param operation   操作类型
     * @param description 操作描述
     * @param params      操作参数
     * @param result      操作结果
     */
    public static void operation(String module, String operation, String description, Object params, Object result) {
        try {
            OperationLogEntity logEntity = buildBaseLogEntity(module, operation, description, LogTypeEnum.OPERATION);
            
            if (params != null) {
                logEntity.setParams(JsonUtil.toJsonString(params));
            }
            
            if (result != null) {
                logEntity.setResult(JsonUtil.toJsonString(result));
            }
            
            logEntity.setStatus(LogStatusEnum.SUCCESS.getCode());
            
            saveLogAsync(logEntity);
        } catch (Exception e) {
            log.error("记录操作日志失败", e);
        }
    }

    /**
     * 记录错误日志
     *
     * @param module    模块名称
     * @param operation 操作类型
     * @param errorMsg  错误信息
     * @param throwable 异常对象
     */
    public static void error(String module, String operation, String errorMsg, Throwable throwable) {
        try {
            OperationLogEntity logEntity = buildBaseLogEntity(module, operation, errorMsg, LogTypeEnum.ERROR);
            logEntity.setStatus(LogStatusEnum.FAILURE.getCode());
            logEntity.setErrorMsg(throwable != null ? throwable.getMessage() : errorMsg);
            
            saveLogAsync(logEntity);
        } catch (Exception e) {
            log.error("记录错误日志失败", e);
        }
    }

    /**
     * 记录性能日志
     *
     * @param module    模块名称
     * @param operation 操作类型
     * @param costTime  耗时（毫秒）
     */
    public static void performance(String module, String operation, long costTime) {
        try {
            OperationLogEntity logEntity = buildBaseLogEntity(module, operation, 
                    String.format("操作耗时: %dms", costTime), LogTypeEnum.PERFORMANCE);
            logEntity.setCostTime(costTime);
            logEntity.setStatus(LogStatusEnum.SUCCESS.getCode());
            
            saveLogAsync(logEntity);
        } catch (Exception e) {
            log.error("记录性能日志失败", e);
        }
    }

    /**
     * 记录安全日志
     *
     * @param module      模块名称
     * @param operation   操作类型
     * @param description 操作描述
     * @param ip          操作IP
     */
    public static void security(String module, String operation, String description, String ip) {
        try {
            OperationLogEntity logEntity = buildBaseLogEntity(module, operation, description, LogTypeEnum.SECURITY);
            logEntity.setIp(ip);
            logEntity.setStatus(LogStatusEnum.SUCCESS.getCode());
            
            saveLogAsync(logEntity);
        } catch (Exception e) {
            log.error("记录安全日志失败", e);
        }
    }

    /**
     * 构建基础日志实体
     */
    private static OperationLogEntity buildBaseLogEntity(String module, String operation, 
                                                        String description, LogTypeEnum logType) {
        OperationLogEntity logEntity = new OperationLogEntity();
        
        // 设置链路追踪ID
        String traceId = MDC.get(LogConstants.TRACE_ID_MDC_KEY);
        if (StringUtils.isEmpty(traceId)) {
            traceId = UUID.randomUUID().toString().replace("-", "");
            MDC.put(LogConstants.TRACE_ID_MDC_KEY, traceId);
        }
        logEntity.setTraceId(traceId);
        
        // 设置用户信息
        try {
            String userId = SessionHelper.getCurrentUserId();
            if (!StringUtils.isEmpty(userId)) {
                logEntity.setUserId(userId);
                // 这里可以根据需要获取用户名
                logEntity.setUserName(userId);
            } else {
                logEntity.setUserId(LogConstants.SYSTEM_USER);
                logEntity.setUserName(LogConstants.SYSTEM_USER);
            }
        } catch (Exception e) {
            logEntity.setUserId(LogConstants.SYSTEM_USER);
            logEntity.setUserName(LogConstants.SYSTEM_USER);
        }
        
        logEntity.setModule(StringUtils.isEmpty(module) ? LogConstants.UNKNOWN_MODULE : module);
        logEntity.setOperation(StringUtils.isEmpty(operation) ? LogConstants.UNKNOWN_OPERATION : operation);
        logEntity.setDescription(description);
        logEntity.setLogType(logType.getCode());
        logEntity.setCreateTime(new Date());
        
        return logEntity;
    }

    /**
     * 异步保存日志
     */
    private static void saveLogAsync(OperationLogEntity logEntity) {
        try {
            ILogService logService = SpringContextUtil.getBean(ILogService.class);
            if (logService != null) {
                logService.saveOperationLogAsync(logEntity);
            }
        } catch (Exception e) {
            log.error("异步保存日志失败", e);
        }
    }
}
